﻿/**********************************************************
 ●项目：Smartkernel
 ●公司：智能核心信息技术研发中心
 ●作者：曹艳白
 ●邮箱：caoyanbai@gmail.com
 ●创建：2008-08-10
**********************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Smartkernel.Attributes;
using Smartkernel.Exceptions;
using Smartkernel.Resource;

namespace Smartkernel.Xml
{
    /// <summary>
    /// XML文件操作功能
    /// </summary>
    public static partial class SmartXml
    {
        #region 公有方法
        /// <summary>
        /// 通过XML文件获得实体，实体必须提供了公有构造函数
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="xmlPath">XML文件地址，XML文件必须遵守特定格式</param>
        /// <param name="smartMappingType">映射的类型</param>
        /// <returns>已经初始化并赋值的实体</returns>
        public static TEntity MappingXO<TEntity>(string xmlPath, SmartMappingType smartMappingType)
        {
            TEntity entity = Activator.CreateInstance<TEntity>();
            MappingXO<TEntity>(xmlPath, smartMappingType, ref entity);
            return entity;
        }
        /// <summary>
        /// 通过XML文件获得实体，实体必须提供了公有构造函数
        /// </summary>
        /// <param name="xmlPath">XML文件地址，XML文件必须遵守特定格式</param>
        /// <param name="smartMappingType">映射的类型</param>
        /// <param name="entity">实体对象</param>
        /// <returns>已经初始化并赋值的实体</returns>
        public static void MappingXO<TEntity>(string xmlPath, SmartMappingType smartMappingType, ref TEntity entity)
        {
            Type type = entity.GetType();
            var xml = XElement.Load(xmlPath);
            var xelements = xml.Descendants();

            switch (smartMappingType)
            {
                case SmartMappingType.Attribute:
                    {
                        #region 根据特性标识映射
                        foreach (PropertyInfo propertyInfo in SmartReflection.GetPropertiesWithAttribute<SmartXmlMappingAttribute>(type))
                        {
                            SmartXmlMappingAttribute attribute = (SmartXmlMappingAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(SmartXmlMappingAttribute), false);
                            string source = null;
                            if (QueryNode(xelements, attribute.NodeName, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, propertyInfo.PropertyType);
                                propertyInfo.SetValue(entity, value, null);
                            }
                            else
                            {
                                if (attribute.DefaultValue != null)
                                {
                                    propertyInfo.SetValue(entity, attribute.DefaultValue, null);
                                }
                            }
                        }
                        foreach (FieldInfo fieldInfo in SmartReflection.GetFieldsWithAttribute<SmartXmlMappingAttribute>(type))
                        {
                            SmartXmlMappingAttribute attribute = (SmartXmlMappingAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(SmartXmlMappingAttribute), false);
                            string source = null;
                            if (QueryNode(xelements, attribute.NodeName, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, fieldInfo.FieldType);
                                fieldInfo.SetValue(entity, value);
                            }
                            else
                            {
                                if (attribute.DefaultValue != null)
                                {
                                    fieldInfo.SetValue(entity, attribute.DefaultValue);
                                }
                            }
                        }
                        #endregion
                    }
                    break;
                case SmartMappingType.Field:
                    {
                        #region 根据字段映射
                        foreach (FieldInfo fieldInfo in SmartReflection.GetFields(type))
                        {
                            string source = null;
                            if (QueryNode(xelements, fieldInfo.Name, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, fieldInfo.FieldType);
                                fieldInfo.SetValue(entity, value);
                            }
                        }
                        #endregion
                    }
                    break;
                case SmartMappingType.Property:
                    {
                        BindingFlags d = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                        MemberInfo[] ms = type.GetMembers(d);

                        #region 根据属性映射
                        foreach (PropertyInfo propertyInfo in SmartReflection.GetProperties(type))
                        {
                            string source = null;
                            if (QueryNode(xelements, propertyInfo.Name, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, propertyInfo.PropertyType);
                                propertyInfo.SetValue(entity, value, null);
                            }
                        }
                        #endregion
                    }
                    break;
            }
        }
        /// <summary>
        /// 通过XML文件获得实体，实体必须提供了公有构造函数
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="xmlPath">XML文件地址，XML文件必须遵守特定格式</param>
        /// <param name="smartMappingType">映射的类型</param>
        /// <returns>已经初始化并赋值的实体列表</returns>
        public static List<TEntity> MappingXOList<TEntity>(string xmlPath, SmartMappingType smartMappingType)
        {
            var xml = XElement.Load(xmlPath);
            var xelements = xml.Descendants();
            List<TEntity> entityList = new List<TEntity>(xelements.Count());
            List<XElement> xelementList = xelements.ToList();
            xelementList.ForEach(delegate(XElement xe) { TEntity entity = Activator.CreateInstance<TEntity>(); Create<TEntity>(xe, ref entity, smartMappingType); entityList.Add(entity); });
            return entityList;
        }
        #endregion
    }
    public static partial class SmartXml
    {
        #region 私有方法
        /// <summary>
        /// 判断指定的节点在文件中是否存在，节点没有值的也认为是不存在
        /// </summary>
        /// <param name="xelements">文件的LINQ查询集合</param>
        /// <param name="node">节点名称</param>
        /// <param name="value">如果存在，则返回节点的值</param>
        /// <returns>是否存在，true表示存在，false表示不存在</returns>
        private static bool QueryNode(IEnumerable<XElement> xelements, string node, out string value)
        {
            var values = from v in xelements where v.Name.ToString().ToLower() == node.ToLower() && v.Value.Trim().Length > 0 select v;
            if (values.Count() > 1)
            {
                throw new SmartException(SmartExceptionMessageResource.SmartXmlConfiger_node_NotOnly);
            }
            else if (values.Count() == 1)
            {
                value = values.First().Value.Trim();
                return true;
            }
            else
            {
                value = string.Empty;
                return false;
            }
        }
        /// <summary>
        /// 通过一个元素创建一个实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="xelement">元素</param>
        /// <param name="entity">实体对象</param>
        /// <param name="smartMappingType">映射的类型</param>
        private static void Create<TEntity>(XElement xelement, ref TEntity entity, SmartMappingType smartMappingType)
        {
            Type type = entity.GetType();

            switch (smartMappingType)
            {
                case SmartMappingType.Attribute:
                    {
                        #region 根据特性标识映射
                        foreach (PropertyInfo propertyInfo in SmartReflection.GetPropertiesWithAttribute<SmartXmlMappingAttribute>(type))
                        {
                            SmartXmlMappingAttribute attribute = (SmartXmlMappingAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(SmartXmlMappingAttribute), false);
                            string source = null;
                            if (QueryAttribute(xelement, attribute.NodeName, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, propertyInfo.PropertyType);
                                propertyInfo.SetValue(entity, value, null);
                            }
                            else
                            {
                                if (attribute.DefaultValue != null)
                                {
                                    propertyInfo.SetValue(entity, attribute.DefaultValue, null);
                                }
                            }
                        }
                        foreach (FieldInfo fieldInfo in SmartReflection.GetFieldsWithAttribute<SmartXmlMappingAttribute>(type))
                        {
                            SmartXmlMappingAttribute attribute = (SmartXmlMappingAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(SmartXmlMappingAttribute), false);
                            string source = null;
                            if (QueryAttribute(xelement, attribute.NodeName, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, fieldInfo.FieldType);
                                fieldInfo.SetValue(entity, value);
                            }
                            else
                            {
                                if (attribute.DefaultValue != null)
                                {
                                    fieldInfo.SetValue(entity, attribute.DefaultValue);
                                }
                            }
                        }
                        #endregion
                    }
                    break;
                case SmartMappingType.Field:
                    {
                        #region 根据字段映射
                        foreach (FieldInfo fieldInfo in SmartReflection.GetFields(type))
                        {
                            string source = null;
                            if (QueryAttribute(xelement, fieldInfo.Name, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, fieldInfo.FieldType);
                                fieldInfo.SetValue(entity, value);
                            }
                        }
                        #endregion
                    }
                    break;
                case SmartMappingType.Property:
                    {
                        #region 根据字段属性
                        foreach (PropertyInfo propertyInfo in SmartReflection.GetProperties(type))
                        {
                            string source = null;
                            if (QueryAttribute(xelement, propertyInfo.Name, out source))
                            {
                                object value = SmartReflection.ConvertTo(source, propertyInfo.PropertyType);
                                propertyInfo.SetValue(entity, value, null);
                            }
                        }
                        #endregion
                    }
                    break;
            }
        }
        /// <summary>
        /// 判断指定的属性在元素中是否存在，属性没有值的也认为是不存在
        /// </summary>
        /// <param name="xelement">元素</param>
        /// <param name="attribute">属性名称</param>
        /// <param name="value">如果存在，则返回属性的值</param>
        /// <returns>是否存在，true表示存在，false表示不存在</returns>
        private static bool QueryAttribute(XElement xelement, string attribute, out string value)
        {
            var values = from v in xelement.Attributes() where v.Name.ToString().ToLower() == attribute.ToLower() && v.Value.Trim().Length > 0 select v;
            if (values.Count() > 1)
            {
                throw new SmartException(SmartExceptionMessageResource.SmartXmlConfiger_attribute_NotOnly);
            }
            else if (values.Count() == 1)
            {
                value = values.First().Value.Trim();
                return true;
            }
            else
            {
                value = string.Empty;
                return false;
            }
        }
        #endregion
    }
}
